const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("SimpleCrossChainAuction", function () {
    let simpleCrossChainAuction;
    let mockRouter;
    let mockNFT;
    let owner;
    let seller;
    let bidder1;
    let bidder2;
    let addrs;

    // 模拟的链选择器
    const ETHEREUM_CHAIN_SELECTOR = 5009297550715157269n; // Ethereum Sepolia
    const POLYGON_CHAIN_SELECTOR = 4051577828743386545n;  // Polygon Mumbai
    const AVALANCHE_CHAIN_SELECTOR = 6433500567565415381n; // Avalanche Fuji

    beforeEach(async function () {
        [owner, seller, bidder1, bidder2, ...addrs] = await ethers.getSigners();

        // 部署模拟路由器
        const MockRouter = await ethers.getContractFactory("MockCCIPRouter");
        mockRouter = await MockRouter.deploy();
        await mockRouter.waitForDeployment();

        // 部署模拟NFT合约
        const MockNFT = await ethers.getContractFactory("MockERC721");
        mockNFT = await MockNFT.deploy("Test NFT", "TNFT");
        await mockNFT.waitForDeployment();

        // 部署SimpleCrossChainAuction
        const SimpleCrossChainAuction = await ethers.getContractFactory("SimpleCrossChainAuction");
        simpleCrossChainAuction = await SimpleCrossChainAuction.deploy(mockRouter.target);
        await simpleCrossChainAuction.waitForDeployment();

        console.log("🌉 SimpleCrossChainAuction deployed to:", simpleCrossChainAuction.target);
        console.log("🔗 Mock Router deployed to:", mockRouter.target);
        console.log("🎨 Mock NFT deployed to:", mockNFT.target);
    });

    describe("🏗️ 部署和初始化", function () {
        it("应该正确设置所有者", async function () {
            expect(await simpleCrossChainAuction.owner()).to.equal(owner.address);
        });

        it("应该正确设置CCIP路由器", async function () {
            expect(await simpleCrossChainAuction.getRouter()).to.equal(mockRouter.target);
        });
    });

    describe("🔗 链管理功能", function () {
        it("应该能添加支持的链", async function () {
            await expect(simpleCrossChainAuction.addSupportedChain(ETHEREUM_CHAIN_SELECTOR))
                .to.emit(simpleCrossChainAuction, "ChainSupportUpdated")
                .withArgs(ETHEREUM_CHAIN_SELECTOR, true);

            expect(await simpleCrossChainAuction.isChainSupported(ETHEREUM_CHAIN_SELECTOR)).to.be.true;
        });

        it("应该能移除支持的链", async function () {
            await simpleCrossChainAuction.addSupportedChain(ETHEREUM_CHAIN_SELECTOR);

            await expect(simpleCrossChainAuction.removeSupportedChain(ETHEREUM_CHAIN_SELECTOR))
                .to.emit(simpleCrossChainAuction, "ChainSupportUpdated")
                .withArgs(ETHEREUM_CHAIN_SELECTOR, false);

            expect(await simpleCrossChainAuction.isChainSupported(ETHEREUM_CHAIN_SELECTOR)).to.be.false;
        });

        it("非所有者不能管理链", async function () {
            await expect(
                simpleCrossChainAuction.connect(bidder1).addSupportedChain(ETHEREUM_CHAIN_SELECTOR)
            ).to.be.revertedWith("SimpleCrossChainAuction: Not owner");
        });
    });

    describe("🎯 拍卖管理功能", function () {
        beforeEach(async function () {
            // 铸造测试NFT
            await mockNFT.mint(seller.address, 1);

            // 添加支持的链
            await simpleCrossChainAuction.addSupportedChain(ETHEREUM_CHAIN_SELECTOR);
            await simpleCrossChainAuction.addSupportedChain(POLYGON_CHAIN_SELECTOR);
        });

        it("应该能初始化拍卖", async function () {
            const startPrice = ethers.parseEther("1");
            const duration = 3600; // 1小时

            await expect(
                simpleCrossChainAuction.initializeAuction(
                    mockNFT.target,
                    1,
                    seller.address,
                    startPrice,
                    duration
                )
            ).to.emit(simpleCrossChainAuction, "AuctionInitialized")
                .withArgs(mockNFT.target, 1, seller.address, startPrice, await time.latest() + duration + 1);

            const auctionInfo = await simpleCrossChainAuction.auctionInfo();
            expect(auctionInfo.nftContract).to.equal(mockNFT.target);
            expect(auctionInfo.tokenId).to.equal(1);
            expect(auctionInfo.seller).to.equal(seller.address);
            expect(auctionInfo.startPrice).to.equal(startPrice);
            expect(auctionInfo.isActive).to.be.true;
        });

        it("应该正确返回拍卖状态", async function () {
            const startPrice = ethers.parseEther("1");
            const duration = 3600;

            await simpleCrossChainAuction.initializeAuction(
                mockNFT.target,
                1,
                seller.address,
                startPrice,
                duration
            );

            const [isActive, isEnded, isSettled, timeRemaining, highestBidAmount] =
                await simpleCrossChainAuction.getAuctionStatus();

            expect(isActive).to.be.true;
            expect(isEnded).to.be.false;
            expect(isSettled).to.be.false;
            expect(timeRemaining).to.be.gt(0);
            expect(highestBidAmount).to.equal(0);
        });

        it("不应该重复初始化拍卖", async function () {
            const startPrice = ethers.parseEther("1");
            const duration = 3600;

            await simpleCrossChainAuction.initializeAuction(
                mockNFT.target,
                1,
                seller.address,
                startPrice,
                duration
            );

            await expect(
                simpleCrossChainAuction.initializeAuction(
                    mockNFT.target,
                    2,
                    seller.address,
                    startPrice,
                    duration
                )
            ).to.be.revertedWith("SimpleCrossChainAuction: Auction already active");
        });
    });

    describe("🌉 跨链出价功能", function () {
        beforeEach(async function () {
            // 设置拍卖
            await mockNFT.mint(seller.address, 1);
            await simpleCrossChainAuction.addSupportedChain(ETHEREUM_CHAIN_SELECTOR);
            await simpleCrossChainAuction.addSupportedChain(POLYGON_CHAIN_SELECTOR);

            const startPrice = ethers.parseEther("1");
            const duration = 3600;

            await simpleCrossChainAuction.initializeAuction(
                mockNFT.target,
                1,
                seller.address,
                startPrice,
                duration
            );
        });

        it("应该能接收和处理跨链出价", async function () {
            const bidAmount = ethers.parseEther("2");

            // 构造CCIP消息
            const messageData = ethers.AbiCoder.defaultAbiCoder().encode(
                ["address", "uint256"],
                [bidder1.address, bidAmount]
            );

            const ccipMessage = {
                messageId: ethers.keccak256("0x1234"),
                sourceChainSelector: ETHEREUM_CHAIN_SELECTOR,
                sender: ethers.AbiCoder.defaultAbiCoder().encode(["address"], [bidder1.address]),
                data: messageData,
                destTokenAmounts: []
            };

            // 模拟CCIP路由器调用
            await expect(
                mockRouter.simulateCCIPReceive(simpleCrossChainAuction.target, ccipMessage)
            ).to.emit(simpleCrossChainAuction, "CrossChainBidReceived")
                .withArgs(ETHEREUM_CHAIN_SELECTOR, bidder1.address, bidAmount, await time.latest() + 1);

            // 检查出价记录
            expect(await simpleCrossChainAuction.getCrossChainBidsCount()).to.equal(1);

            const highestBid = await simpleCrossChainAuction.highestBid();
            expect(highestBid.bidder).to.equal(bidder1.address);
            expect(highestBid.amount).to.equal(bidAmount);
            expect(highestBid.sourceChain).to.equal(ETHEREUM_CHAIN_SELECTOR);
        });

        it("应该正确更新最高出价", async function () {
            const bid1Amount = ethers.parseEther("2");
            const bid2Amount = ethers.parseEther("3");

            // 第一次出价
            const messageData1 = ethers.AbiCoder.defaultAbiCoder().encode(
                ["address", "uint256"],
                [bidder1.address, bid1Amount]
            );

            const ccipMessage1 = {
                messageId: ethers.keccak256("0x1234"),
                sourceChainSelector: ETHEREUM_CHAIN_SELECTOR,
                sender: ethers.AbiCoder.defaultAbiCoder().encode(["address"], [bidder1.address]),
                data: messageData1,
                destTokenAmounts: []
            };

            await mockRouter.simulateCCIPReceive(simpleCrossChainAuction.target, ccipMessage1);

            // 第二次更高出价
            const messageData2 = ethers.AbiCoder.defaultAbiCoder().encode(
                ["address", "uint256"],
                [bidder2.address, bid2Amount]
            );

            const ccipMessage2 = {
                messageId: ethers.keccak256("0x5678"),
                sourceChainSelector: POLYGON_CHAIN_SELECTOR,
                sender: ethers.AbiCoder.defaultAbiCoder().encode(["address"], [bidder2.address]),
                data: messageData2,
                destTokenAmounts: []
            };

            await mockRouter.simulateCCIPReceive(simpleCrossChainAuction.target, ccipMessage2);

            // 检查最高出价
            const highestBid = await simpleCrossChainAuction.highestBid();
            expect(highestBid.bidder).to.equal(bidder2.address);
            expect(highestBid.amount).to.equal(bid2Amount);
            expect(highestBid.sourceChain).to.equal(POLYGON_CHAIN_SELECTOR);

            expect(await simpleCrossChainAuction.getCrossChainBidsCount()).to.equal(2);
        });

        it("应该拒绝来自不支持链的出价", async function () {
            const bidAmount = ethers.parseEther("2");

            const messageData = ethers.AbiCoder.defaultAbiCoder().encode(
                ["address", "uint256"],
                [bidder1.address, bidAmount]
            );

            const ccipMessage = {
                messageId: ethers.keccak256("0x1234"),
                sourceChainSelector: AVALANCHE_CHAIN_SELECTOR, // 未支持的链
                sender: ethers.AbiCoder.defaultAbiCoder().encode(["address"], [bidder1.address]),
                data: messageData,
                destTokenAmounts: []
            };

            await expect(
                mockRouter.simulateCCIPReceive(simpleCrossChainAuction.target, ccipMessage)
            ).to.be.revertedWith("SimpleCrossChainAuction: Unsupported source chain");
        });
    });

    describe("🏁 拍卖结算", function () {
        beforeEach(async function () {
            await mockNFT.mint(seller.address, 1);
            await simpleCrossChainAuction.addSupportedChain(ETHEREUM_CHAIN_SELECTOR);

            const startPrice = ethers.parseEther("1");
            const duration = 1; // 1秒，便于测试

            await simpleCrossChainAuction.initializeAuction(
                mockNFT.target,
                1,
                seller.address,
                startPrice,
                duration
            );
        });

        it("应该能在拍卖结束后结算", async function () {
            // 等待拍卖结束
            await time.increase(2);

            await expect(simpleCrossChainAuction.settleAuction())
                .to.not.be.reverted;

            const auctionInfo = await simpleCrossChainAuction.auctionInfo();
            expect(auctionInfo.isActive).to.be.false;
            expect(auctionInfo.isSettled).to.be.true;

            const [isActive, isEnded, isSettled] = await simpleCrossChainAuction.getAuctionStatus();
            expect(isActive).to.be.false;
            expect(isEnded).to.be.true;
            expect(isSettled).to.be.true;
        });

        it("不应该在拍卖进行中结算", async function () {
            await expect(simpleCrossChainAuction.settleAuction())
                .to.be.revertedWith("SimpleCrossChainAuction: Auction not ended");
        });

        it("不应该重复结算", async function () {
            await time.increase(2);
            await simpleCrossChainAuction.settleAuction();

            await expect(simpleCrossChainAuction.settleAuction())
                .to.be.revertedWith("SimpleCrossChainAuction: Already settled");
        });
    });

    describe("👑 所有权管理", function () {
        it("应该能转移所有权", async function () {
            await simpleCrossChainAuction.transferOwnership(bidder1.address);
            expect(await simpleCrossChainAuction.owner()).to.equal(bidder1.address);
        });

        it("不应该转移给零地址", async function () {
            await expect(
                simpleCrossChainAuction.transferOwnership(ethers.ZeroAddress)
            ).to.be.revertedWith("SimpleCrossChainAuction: Invalid new owner");
        });

        it("非所有者不能转移所有权", async function () {
            await expect(
                simpleCrossChainAuction.connect(bidder1).transferOwnership(bidder2.address)
            ).to.be.revertedWith("SimpleCrossChainAuction: Not owner");
        });
    });
});

// 辅助函数
const time = {
    latest: async () => {
        const block = await ethers.provider.getBlock("latest");
        return block.timestamp;
    },
    increase: async (seconds) => {
        await ethers.provider.send("evm_increaseTime", [seconds]);
        await ethers.provider.send("evm_mine");
    }
};
